#!/usr/bin/env python


from optparse import Option, OptionParser, OptionContainer, \
     OptionGroup, OptionValueError
from time import time, asctime, gmtime, strftime, sleep
from copy import copy

import sys
sys.path.append("/SVN/sma-vlbi")
from remoteQueue import remoteQueue


RANGE_MARKER = ".."
FMTS = { "delays": "%.1f",
         "phases": "%3d",
         "gains": "%3d" }


def import_for_server():
    """This function contains the imports needed when starting
    the server daemon; it also contains various class definitions,
    the server itself, a data structure, and logging handlers."""
    global daemon, logging, fill, atan2, sqrt, fft, array, real, imag
    import os
    import daemon
    import logging
    import logging.handlers
    from textwrap import fill
    from math import pi, sin, asin, cos, acos, atan, atan2, sqrt
    from numpy.fft import fft
    from numpy import array, real, imag, sqrt, dot, fromfunction
    from phasedarray import PhasedArray

      ##
      ##   Custom Logging
      ##     File Handler
    ######     & Formatter
     ####
      ##
    ############################

    global MidnightRotatingFileHandler
    class MidnightRotatingFileHandler(logging.handlers.BaseRotatingHandler):
        """ A logger class to replace TimedRotatingFileHandler
        but only for 'midnight' rotating cases.

        The original class did some funky things when issuing
        a doRollover which aren't really appropriate for this
        application. E.g. it renames the current log to the next
        suffix iteration but continues to use the baseFilename.
        How that made sense to the original author I have no clue."""

        def __init__(self, filename):
            self.filename = filename
            self.suffix = "%Y-%m-%d"
            self.date = strftime(self.suffix,
                                 gmtime())

            current_log = self.filename + "." + self.date
            logging.handlers.BaseRotatingHandler.__init__(self,
                                                          current_log,
                                                          'a', encoding=None)

        def shouldRollover(self, record):
            """If the date has changed do a rollover."""
            date = strftime(self.suffix, gmtime())
            if self.date <> date:
                self.date = date
                return True
            else:
                return False

        def doRollover(self):
            self.stream.close()
            self.stream = open(self.filename + "." + self.date, 'a')


    global FixedWidthFormatter
    class FixedWidthFormatter(logging.Formatter):
        """Overrides the format method to provide for a textwrapped
        version of a log entry"""

        def __init__(self, width, fmt=None, datefmt=None, separators={}):
            self.width = width
            self.separators = {}
            self.default_separators = { 'DEBUG' : '-',
                                        'INFO' : '+',
                                        'NOTE' : '*',
                                        'ERROR' : '^',
                                        'WARNING' : '#' }

            for s in self.default_separators:
                su = s.upper()
                if s not in separators:
                    self.separators[su] = self.default_separators[su]
                else:
                    self.separators[su] = separators[su]

            logging.Formatter.__init__(self, fmt=fmt, datefmt=datefmt)

        def format(self, record):
            s = logging.Formatter.format(self, record)
            separator = self.separators[record.levelname] * self.width
            return separator +"\n" + fill(s, self.width)

    ############################
      ##
     ####
    ######
      ##   Custom Logging
      ##     File Handler
      ##       & Formatter


      ##
      ##   PhringesData
      ##
    ######
     ####
      ##
    ############################

    global PhringesData
    class PhringesData:
        """A container class that holds PHRINGES scans
        but also performs related calculations."""
        def __init__(self, correlations={}, recorded_at=0.0):
            self.correlations = correlations
            self.recorded_at = recorded_at
            self.phases = dict((i,self.get_phase(c)) \
                                   for i,c in self.correlations.iteritems())
            self.magnitudes = dict((i,self.get_magnitude(c)) \
                                       for i,c in self.correlations.iteritems())

        def reorder(self, correlation):
            positive = correlation[int(len(correlation)/2.0):len(correlation)]
            negative = correlation[0:int(len(correlation)/2.0)]
            return positive + negative

        def get_complex_fft(self, correlation):
            corr_array = array(self.reorder(correlation)).astype('d')
            return fft(corr_array)

        def get_real_imag(self, correlation, coeff=1):
            complex = coeff*self.get_complex_fft(correlation)
            return real(complex), imag(complex)

        def get_phase(self, correlation, coeff=1):
            #real__, imag__ = self.get_real_imag(correlation, coeff)
            real__, imag__ = self.spline_interp_real_imag(correlation, coeff)
            real_ = [1.0] + real__.tolist()
            imag_ = [0.0] + imag__.tolist()
            global dirs
            dirs = []
            phase = []
            del_phase = []
            def mag(vector):
                return sqrt(dot(vector, vector))
            for i in range(len(real_)-1):
                a = array((real_[i], imag_[i])).astype('d')
                b = array((real_[i+1], imag_[i+1])).astype('d')
                cross = b[1] * a[0] - a[1] * b[0]
                if cross <> 0.0:
                    dir = cross / abs(cross)
                else:
                    dir = 1
                dirs.append(dir)
                angle = dir * acos(dot(a,b) / (mag(a) * mag(b)))
                del_phase.append(angle)
                phase.append(sum(del_phase))
            return array(phase).astype('d')

        def spline_interp_real_imag(self, correlation, coeff=1):
            real_, imag_ = self.get_real_imag(correlation, coeff)
            from numpy import r_
            from scipy.signal import cspline1d, cspline1d_eval
            freq = r_[0:len(real_)]
            dfreq = freq[1] - freq[0]
            newfreq = r_[0:len(real_):0.1]
            csreal = cspline1d(real_)
            csimag = cspline1d(imag_)
            newreal = cspline1d_eval(csreal, newfreq, dx=dfreq, x0=freq[0])
            newimag = cspline1d_eval(csimag, newfreq, dx=dfreq, x0=freq[0])
            return newreal, newimag

        def get_phase_atan(self, correlation, coeff=1):
            real_, imag_ = self.get_real_imag(correlation, coeff)
            return array([float(atan2(imag_[j], real_[j])) \
                              for j in range(len(real_))]).astype('d')

        def get_magnitude(self, correlation):
            real_, imag_ = self.get_real_imag(correlation)
            return array([float(sqrt(real_[j]**2 + imag_[j]**2)) \
                          for j in range(len(real_))])

        def wrap_phase(self, phase):
            phase = list(phase)
            for i in range(len(phase)):
                start = phase[:i]
                end = array(phase[i:])
                if phase[i] > pi:
                    phase = start + \
                        list(end - 2*pi)
                elif phase[i] <= -pi:
                    phase = start + \
                        list(end + 2*pi)
                else:
                    pass
            return array(phase).astype('d')

    ############################
      ##
     ####
    ######
      ##
      ##   PhringesData
      ##


      ##
      ##   PhringesServer
      ##
    ######
     ####
      ##
    ############################

    global PhringesServer
    class PhringesServer(remoteQueue):
        """Not yet fully implemented."""
        _quit = False
        mapping, phases, delays, gains = [{} for i in range(4)]

        #
       ### Setup
       ###   functions
        #

        def setup_phased_array(self):
            self.pa = PhasedArray()

        def setup_logger(self):
            logging.NOTE = 25
            logging.addLevelName(logging.NOTE, "NOTE")
            logging.root.setLevel([logging.DEBUG, logging.INFO,
                                   logging.NOTE, logging.WARNING,
                                   logging.ERROR, logging.CRITICAL])
            self.logger = logging.getLogger("Server")
            self.logger.setLevel(logging.DEBUG)
            info = MidnightRotatingFileHandler("/logs/phringes")
            debug = MidnightRotatingFileHandler("/logs/phringes.debug")
            console = logging.StreamHandler()
            fmtr = FixedWidthFormatter(40,
                                       fmt="%(asctime)s (UTC) - "
                                       "%(levelname)s - "
                                       "%(name)s: %(message)s", 
                                       separators={'INFO':'#',
                                                   'NOTE':'='})
            con_fmtr = logging.Formatter("%(asctime)s (UTC) - "
                                         "%(levelname)s - %(message)s")
            fmtr.converter = gmtime
            info.setFormatter(fmtr)
            debug.setFormatter(fmtr)
            console.setFormatter(con_fmtr)
            info.setLevel(logging.INFO)
            debug.setLevel(logging.DEBUG)
            console.setLevel(logging.DEBUG)
            self.logger.addHandler(info)
            self.logger.addHandler(debug)
            self.logger.addHandler(console)

        #
       ### Logging
       ###   macros
        #

        def debug(self, message):
            self.logger.debug(message)

        def info(self, message):
            self.logger.info(message)

        def note(self, message):
            self.logger.log(logging.NOTE,
                            message)

        def warning(self, message):
            self.logger.warning(message)

        def error(self, message):
            self.logger.error(message)

        # 
       ### Server Admin
       ###   handlers
        #

        def start(self):
            """This basically exposes the PhringesServer
            class methods and attributes to remoteQueue;
            it also starts the logger."""
            self.setup_phased_array()
            self.setup_logger()
            self.started_at = time()
            self.put(("star",None))
            self.info("PHRINGES server started.")
            while not self._quit:
                action, value = self.get()
                try:
                    handler = getattr(self, action)
                    handler(value)
                except AttributeError:
                    self.debug("No action: %s" % action)

        def stop(self, value):
            self._quit = True
            self.put(("exit",time()))
            self.info("Exit server.")

        def ping(self, value):
            self.put(("pong",self.started_at))
            self.note("Ping received, pong sent.")

        # 
       ### Mapping
       ###   handlers
        #
        
        def mapp(self, value):
            self.mapping.update(value)
            self.note("New mapping received: %s" % value)

        def gmap(self, value):
            self.put(("mval",self.mapping))
            self.note("Mapping requested and sent. "
                      "Current mapping: %s" % self.mapping)

        # 
       ### Delay
       ###   handlers
        #

        def dela(self, value):
            self.pa.setDelays(value)
            self.delays.update(value)
            self.note("New delays received: %s" % value)

        def gdel(self, value):
            self.pa.getDelays()
            if self.pa.delays <> self.delays:
                self.delays.update(self.pa.delays)
            self.put(("dval",self.delays))
            self.note("Delays requested and sent. "
                      "Current delays: %s" % self.delays)

        # 
       ### Phase
       ###   handlers
        #

        def phas(self, value):
            self.phases.update(value)
            self.note("New phases received: %s" % value)

        def gpha(self, value):
            self.put(("pval",self.phases))
            self.note("Phases requested and sent. "
                      "Current phases: %s" % self.phases)

        # 
       ### Gain
       ###   handlers
        #

        def gain(self, value):
            self.gains.update(value)
            self.note("New gains received: %s" % value)

        def ggai(self, value):
            self.put(("gval",self.gains))
            self.note("Gains requested and sent. "
                      "Current gains: %s" % self.gains)

            
    ############################
      ##
     ####
    ######
      ##
      ##   PhringesServer
      ##


  ##
  ##   Protocol
  ##     Handlers
######
 ####
  ##
############################

def server_is_alive(phringes, timeout, tries):
    ping = ("ping", None)
    phringes.put(ping)
    for t in range(tries):
        resp = phringes.get(timeout=timeout)
        if resp[0] == "pong":
            return resp[1]  # this is the server start time
    return False

def check_peers(phringes):
    if len(phringes._peers) == 0:
        raise OptionValueError("No peers found, "
                               "have you started the server?")

def check_for_server(phringes, timeout=10, tries=10):
    check_peers(phringes)
    if not server_is_alive(phringes, timeout, tries):
        raise OptionValueError("Server is not responding, "
                               "have you started the server?")

def request_item(phringes, name, item):
    check_for_server(phringes)
    phringes.put((name,None))
    action = None
    while action <> item:
        action, value = phringes.get()
    return value

def return_mapping(phringes):
    return request_item(phringes,
                        "gmap",
                        "mval")

def return_delays(phringes):
    return request_item(phringes,
                        "gdel",
                        "dval")

def return_phases(phringes):
    return request_item(phringes,
                        "gpha",
                        "pval")

def return_gains(phringes):
    return request_item(phringes,
                        "ggai",
                        "gval")

def return_item(phringes, item_name):
    if item_name == "delays":
        return return_delays(phringes)
    elif item_name == "phases":
        return return_phases(phringes)
    elif item_name == "gains":
        return return_gains(phringes)
    else:
        pass

############################
  ##
 ####
######
  ##
  ##   Protocol
  ##     Handlers


  ##
  ##   Command-line
  ##     Option Callbacks
######
 ####
  ##
############################

def start_server(option, opt_str, value, parser):
    import_for_server()
    if parser.values.daemon:
        print "Starting the PHRINGES server as a daemon."
        daemon.daemonize()
    phringes = PhringesServer()
    phringes.start()

def check_server(option, opt_str, value, parser):
    phringes = remoteQueue()
    check_peers(phringes)
    start_time = server_is_alive(phringes, 10, 10)
    if start_time:
        print "Server process was started at %s" \
              % asctime(gmtime(start_time))
    else:
        print "Server is not responding!"

def restart_server(option, opt_str, value, parser):
    stop_server(option, opt_str, value, parser)
    start_server(option, opt_str, value, parser)

def stop_server(option, opt_str, value, parser):
    phringes = remoteQueue()
    check_for_server(phringes)
    phringes.put(("stop",None))
    action_count = 0
    action = None
    while action <> "exit":
        action_count += 1
        action, value = phringes.get()
    print "Server exited at %s, after completing %d actions." \
          % (asctime(gmtime(value)), action_count)

def start_delay_tracking(option, opt_str, value, parser):
    """Not yet implemented."""

def stop_delay_tracking(option, opt_str, value, parser):
    """Not yet implemented."""

def start_phase_tracking(option, opt_str, value, parser):
    """Not yet implemented."""
    
def stop_phase_tracking(option, opt_str, value, parser):
    """Not yet implemented."""

def set_mapping(option, opt_str, value, parser):
    phringes = remoteQueue()
    check_for_server(phringes)
    mapping = {}
    antennas = parser.values.antennas
    inputs = parser.values.inputs
    if len(antennas) <> len(inputs):
        raise OptionValueError(
            "%d antennas cannot be mapped to %d inputs"
            % (len(antennas), len(inputs)))
    for i in range(len(antennas)):
        mapping[antennas[i]] = inputs[i]
    keys = mapping.keys()
    keys.sort()
    print " SMA : PHRINGES"
    for a in keys:
        print " %2d  : %2d" % (a,mapping[a])
    if raw_input("Is the above mapping correct? [Y/n] ") in ["Y", "y", ""]:
        phringes.put(("mapp",mapping))
        print "Mapping successfully set."

def set_item(option, opt_str, value, parser,
             item_name, units):
    phringes = remoteQueue()
    antennas = parser.values.antennas
    inputs = parser.values.inputs
    mapping = return_mapping(phringes)
    item = {}
    if parser.values.prompt: 
        print " ANTENNA : INPUT : %s" % item_name.upper()[0:-1]
    for a,i in mapping.iteritems():
        if a in antennas or i in inputs:
            if parser.values.prompt:
                format = "     %2d  :   %2d  : "+FMTS[item_name]+"%s"
                print format  % (a,i,value,units)
            item[i] = value
    if parser.values.prompt:
        prompt = "Are the above %s correct? [Y/n] " % item_name
        if raw_input(prompt) in ["Y", "y", ""]:
            phringes.put((item_name[:4],item))
            print "%s set successfully." % item_name.capitalize()
    else:
        phringes.put((item_name[:4],item))
    
def set_delays(option, opt_str, value, parser):
    set_item(option, opt_str, value, parser,
             "delays", "ns")

def set_phases(option, opt_str, value, parser):
    set_item(option, opt_str, value, parser,
             "phases", u"\u00b0")

def set_gains(option, opt_str, value, parser):
    set_item(option, opt_str, value, parser,
             "gains", "%")

def get_mapping(option, opt_str, value, parser):
    phringes = remoteQueue()
    antennas = parser.values.antennas
    inputs = parser.values.inputs
    mapping = return_mapping(phringes)
    print " SMA : PHRINGES"
    for a,i in mapping.iteritems():
        if a in antennas or i in inputs:
            print " %2d  : %2d" % (a,i)

def get_item(option, opt_str, value, parser, 
             item_name, units):
    phringes = remoteQueue()
    antennas = parser.values.antennas
    inputs = parser.values.inputs
    mapping = return_mapping(phringes)
    item = return_item(phringes, item_name)
    print " ANTENNA : INPUT : %s" % item_name.upper()[0:-1]
    for a,i in mapping.iteritems():
        if a in antennas or i in inputs:
            format = "     %2d  :   %2d  : "+FMTS[item_name]+"%s"
            print format % (a,i,item[i],units)

                

def get_delays(option, opt_str, value, parser):
    get_item(option, opt_str, value, parser,
             "delays", "ns")

def get_phases(option, opt_str, value, parser):
    get_item(option, opt_str, value, parser,
             "phases", u"\u00b0")

def get_gains(option, opt_str, value, parser):
    get_item(option, opt_str, value, parser,
             "gains", "%")

############################
  ##
 ####
######
  ##
  ##   Command-line
  ##     Option Callbacks


  ##
  ##   Custom Option-
  ##     Parser Definitions
######
 ####
  ##
############################

def check_tuple_str(option, opt, value):
    """Parses a command-line string into a tuple."""
    return value.split(",")

def gen_tuple_int(string_):
    """Parses a command-line string into a tuple of integers.
    Allows for inputs such as 1-4,7 or 0-9, etc."""
    for s in string_.split(','):
        range_ = s.split(RANGE_MARKER)
        if len(range_) == 2:
            try:
                a = int(range_[0])        #
                b = int(range_[1])       ## b+1 needed to accomodate
                for i in range(a,b+1):  ### the human tendency to
                    yield i              ## index from 1
            except ValueError:            #
                raise OptionValueError(
                    "invalid range: %s-%s" % (a,b))
        else:
            try:
                yield int(s)
            except ValueError:
                raise OptionValueError(
                    "invalid integer: %s" % s)

def check_tuple_int(option, opt, value):
    """Simply returns a tuple generated by the above generator"""
    return tuple(gen_tuple_int(value))

def check_tuple_float(option, opt, value):
    """Parses a command-line string into a tuple of floats."""
    flts = []
    strgs = value.split(",")
    for s in strgs:
        try:
            flts.append(float(s))
        except ValueError:
            raise OptionValueError(
                "option %s: invalid float: %s" % (opt, s))
    return tuple(flts)


class PhringeOption(Option):
    """This adds the functionality that the store action
    only stores a default value if all other arguments in the
    default_if_none are not given.

    It also overwrites the callback action so that callbacks
    are evaluated after all other arguments have been parsed.
    This allows options performing functions that require other
    options to be specified anywhere on the command-line."""

    ATTRS = Option.ATTRS + ["default_if_none",
                            "others",]
    TYPES = Option.TYPES + ("tuple_str",
                            "tuple_int",
                            "tuple_float",)

    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
    TYPE_CHECKER["tuple_str"] = check_tuple_str
    TYPE_CHECKER["tuple_int"] = check_tuple_int
    TYPE_CHECKER["tuple_float"] = check_tuple_float
    
    def take_action(self, action, dest, opt, value, values, parser):
        """Here the store action is overwritten to provide the
        functionality described above.
        
        Also, the callback action is overwritten so that callbacks are 
        stored in a CALLBACKS set in OptionParser and then later called 
        one-by-one by the parse_args member function."""
        if action == 'store':
            args = set(parser._get_args(None))
            for o in self.others:
                option = parser.get_option(o)
                opts = set(str(option).split("/"))
                if args&opts == set([]):
                    setattr(values, option.dest, option.default_if_none)
                    setattr(values, dest, value)
                else:
                    setattr(values, dest, value)
        elif action == 'callback':
            args = self.callback_args or ()
            kwargs = self.callback_kwargs or {}
            parser.CALLBACKS.add((self.callback, self, opt,
                                  value, parser, args, 
                                  tuple((k,v) for k,v in
                                        kwargs.iteritems())))
        else:
            Option.take_action(self, action, dest, opt,
                               value, values, parser)


class PhringeOptionParser(OptionParser):
    """See above for the purpose of this subclass."""

    CALLBACKS = set()

    def parse_args(self, args=None, values=None):
        """The parse_args member function is overwritten here so that 
        the original function is called, but because of the code above
        callbacks are stored instead of evaluated, and then one-by-one
        callbacks are evaluated."""

        (options, args) =  OptionParser.parse_args(self, args, values)
        for callback_tuple in parser.CALLBACKS:
            callback_ = callback_tuple[0]
            self_ = callback_tuple[1]
            opt_ = callback_tuple[2]
            value_ = callback_tuple[3]
            parser_ = callback_tuple[4]
            args_ = callback_tuple[5]
            kwargs_ = dict(callback_tuple[6])
            callback_(self_, opt_, value_, parser_, *args_, **kwargs_)
        return (options, args)

############################
  ##
 ####
######
  ##
  ##   Custom Option-
  ##     Parser Definitions


  ##
  ##   Parser
  ##     Options
######
 ####
  ##
############################

parser = PhringeOptionParser(option_class=PhringeOption,
                             version="%prog 1.0.0")

parser.add_option("-v",
                  action="version",
                  help="same as --version")


display_group = OptionGroup(parser, "Display Options",
                            "Use these to control the amount of debug output printed to "
                            "the screen.")
display_group.add_option("--not-daemon",
                         action="store_false",
                         dest="daemon",
                         default=True,
                         help="only meaningful with --start-server; runs "
                         "the server as a blocking process; it will also print "
                         "debug information to stdout.")
display_group.add_option("-n",
                         "--no-prompt",
                         action="store_false",
                         dest="prompt",
                         default=True,
                         help="sets values without asking for confirmation.")
parser.add_option_group(display_group)


server_group = OptionGroup(parser, "Server Options",
                           "These options control the server daemon and "
                           "other processes related to delay and phase "
                           "tracking.")
server_group.add_option("--start-server",
                        action="callback",
                        callback=start_server,
                        help="starts the PHRINGES server.")
server_group.add_option("--check-server",
                        action="callback",
                        callback=check_server,
                        help="checks to see if the PHRINGES server "
                        "has been started.")
server_group.add_option("--restart-server",
                        action="callback",
                        callback=restart_server,
                        help="kills and then restarts the PHRINGES server.")
server_group.add_option("--stop-server",
                        action="callback",
                        callback=stop_server,
                        help="permanently kills the PHRINGES server.")
server_group.add_option("--start-delay-tracking",
                        action="callback",
                        callback=start_delay_tracking,
                        help="starts the geometric delay tracking thread.")
server_group.add_option("--stop-delay-tracking",
                        action="callback",
                        callback=stop_delay_tracking,
                        help="kills geometric delay tracking.")
server_group.add_option("--start-phase-tracking",
                        action="callback",
                        callback=start_phase_tracking,
                        help="starts automated phase correction.")
server_group.add_option("--stop-phase-tracking",
                        action="callback",
                        callback=stop_phase_tracking,
                        help="stops automatic phase correction.")
parser.add_option_group(server_group)


required_group = OptionGroup(parser, "Antenna/Input Declarations",
                             "The default for these is simply the whole "
                             "array but specifying a particular list or "
                             "range limits actions to those particular "
                             "antennas or PHRINGES inputs.")
required_group.add_option("-a",
                          "--antennas",
                          action="store",

                          type="tuple_int",
                          dest="antennas",
                          default=range(1,9),
                          default_if_none=[],
                          others=["--inputs",],
                          help="selects a subset of SMA antennas.")
required_group.add_option("-i",
                          "--inputs",
                          action="store",
                          type="tuple_int",
                          dest="inputs",
                          default=range(0,8),
                          default_if_none=[],
                          others=["--antennas",],
                          help="selects a subset of PHRINGES inputs.")
parser.add_option_group(required_group)


interface_group = OptionGroup(parser, "Interface Options",
                              "These options control the interface "
                              "between the SMA and PHRINGES.")
interface_group.add_option("-m",
                           "--mapping",
                           action="callback",
                           callback=set_mapping,
                           help="sets the SMA-to-PHRINGES (i.e. "
                           "antenna-to-input mapping); if you don't supply "
                           "either -a or -i the defaults will be used: SMA "
                           "antennas 1..8 will be mapped to PHRINGES inputs "
                           "0..7")
interface_group.add_option("--get-mapping",
                           action="callback",
                           callback=get_mapping,
                           help="gets the current SMA-to-PHRINGES (i.e. "
                           "antenna-to-input mapping) from the server; "
                           "This defaults to displaying the full array "
                           "map but specifying a range (via -i) limits "
                           "output.")
parser.add_option_group(interface_group)


calibration_group = OptionGroup(parser, "Calibration Options",
                                "Use these commands to set initial "
                                "calibration parameters and offsets; "
                                "they also provide the ability "
                                "to read back calibration details "
                                "from the correlator. ")
calibration_group.add_option("-d",
                             "--delays",
                             action="callback",
                             callback=set_delays,
                             type="float",
                             help="sets the delays of PHRINGES inputs; "
                             "be sure to include the -i option and the "
                             "list of inputs to apply the given delay to.")
calibration_group.add_option("--get-delays",
                             action="callback",
                             callback=get_delays,
                             help="gets the current delay settings from the "
                             "PHRINGES server.")
calibration_group.add_option("-p",
                             "--phases",
                             action="callback",
                             callback=set_phases,
                             type="int",
                             help="sets the phases of PHRINGES inputs; "
                             "the same requirements apply as for the delay "
                             "option except valid phases must be given as "
                             "integer degrees.")
calibration_group.add_option("--get-phases",
                             action="callback",
                             callback=get_phases,
                             help="gets the current phase settings from the "
                             "PHRINGES server.")
parser.add_option_group(calibration_group)


vlbi_group = OptionGroup(parser, "VLBI Options",
                         "These options control parameters for the "
                         "VLBI digital backend subsystem of PHRINGES; "
                         "specifically those concerned formatting the "
                         "summed data for high-speed storage.")
vlbi_group.add_option("-g",
                      "--gains",
                      action="callback",
                      callback=set_gains,
                      type="int",
                      help="sets the gains of the summed ouput which "
                      "can be used to include/exclude antennas from "
                      "the sum or to optimize the sum via Tsys or "
                      "other considerations. Accepts an integer "
                      "percent as the gain.")
vlbi_group.add_option("--get-gains",
                      action="callback",
                      callback=get_gains,
                      help="gets the current gain settings from the "
                      "PHRINGES server.")
parser.add_option_group(vlbi_group)

############################
  ##
 ####
######
  ##
  ##   Parser
  ##     Options


(options, args) = parser.parse_args()


if 'monitor' not in args:
    if parser._get_args(None) == []:
        pass
    else:
        exit()


  ##
  ##   PhringesMonitor
  ##     using nCurses
######
 ####
  ##
############################


import curses
from threading import Thread


class PhringesMonitor(Thread):
    """Not yet fully implemented."""
    def __init__(self, win, phringes):
        self.win = win
        self.phringes = phringes
        self._quit = False
        self._server_stopped = False
        Thread.__init__(self)
        
    def run(self):
        while not self._quit:
            action, value = self.phringes.get()
            if action == "exit":
                self._server_stopped = True 
                self.update_server_status()
            elif action == "star":
                self._server_stopped = False
                self.update_server_status()
            elif action == "dval":
                self.delays = value
                self.update_delays()

    def update_server_status(self):
        self.win.erase()
        if not self._server_stopped:
            self.win.addstr(1,1,"Server has been started!")
        else:
            self.win.addstr(1,1,"Sever cannot be reached or "
                            "has not been started.")
        self.win.refresh()

    def update_delays(self):
        self.win.erase()
        n = 0
        for i,d in self.delays.iteritems():
            self.win.addstr(3+n,1,"%3d : %3d"%(i,d))
            n += 1
        self.win.refresh()


def main(stdscr):
    phringes = remoteQueue()
    check_for_server(phringes)
    quit = False
    mainwin = curses.newwin(0,0)
    monitor = PhringesMonitor(mainwin, phringes)
    monitor.setDaemon(True)
    monitor.start()
    while not quit:
        c = stdscr.getkey()
        if c == 'q':
            quit = True
        else:
            pass


if __name__ == "__main__":
    curses.wrapper(main)
